package msgcenter

import (
	"context"
	"sync"
)

// Call超时控制
type callTimeout struct {
	ctx    context.Context
	cancel context.CancelCauseFunc

	// 确保 Response 与 Cancel 在并发下不会存在同时操作的情况
	resOnce *sync.Once
	resChan chan []byte

	// 过期时间戳 -1不过期
	deadline int64
}

func (w *callTimeout) Init(ctx context.Context, deadline int64) {
	w.ctx, w.cancel = context.WithCancelCause(ctx)
	w.resOnce = new(sync.Once)
	w.resChan = make(chan []byte)
	w.deadline = deadline
}

func (w *callTimeout) Reset() {
	close(w.resChan)
	w.ctx = nil
	w.cancel = nil
	w.resOnce = nil
	w.resChan = nil
	w.deadline = -1
}

func (w *callTimeout) Wait() (data []byte, err error) {
	select {
	case <-w.ctx.Done():
		err = context.Cause(w.ctx)
	case data = <-w.resChan:
	}
	return
}

func (w *callTimeout) Response(data []byte) (err error) {
	w.resOnce.Do(func() {
		select {
		case <-w.ctx.Done():
			err = context.Cause(w.ctx)
		case w.resChan <- data:
			// 正常退出
			w.cancel(nil)
		}
	})

	return
}

func (w *callTimeout) Cancel(err error) {
	w.resOnce.Do(func() {
		w.cancel(err)
	})
}

func (w *callTimeout) CheckTimeout(now int64) bool {
	if w.deadline != -1 {
		return w.deadline <= now
	}

	return false
}
